/*
 * ChessGUI.java
 */

/* Copyright information:
 * 
 *  Copyright 2010 Failboat Productions. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 * 
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 * 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY FAILBOAT PRODUCTIONS ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FAILBOAT PRODUCTIONS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Failboat Productions.
 */

package GUI;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.Thread.State;
import java.util.ArrayList;

import pieces.Bishop;
import pieces.Knight;
import pieces.Piece;
import pieces.Queen;
import pieces.Rook;
import pieces.Piece.ChessColor;

import com.trolltech.qt.core.QSettings;
import com.trolltech.qt.core.Qt;
import com.trolltech.qt.core.Qt.AlignmentFlag;
import com.trolltech.qt.gui.QAction;
import com.trolltech.qt.gui.QApplication;
import com.trolltech.qt.gui.QCloseEvent;
import com.trolltech.qt.gui.QColor;
import com.trolltech.qt.gui.QDialog;
import com.trolltech.qt.gui.QFileDialog;
import com.trolltech.qt.gui.QFont;
import com.trolltech.qt.gui.QGridLayout;
import com.trolltech.qt.gui.QHBoxLayout;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.gui.QKeySequence;
import com.trolltech.qt.gui.QLabel;
import com.trolltech.qt.gui.QMainWindow;
import com.trolltech.qt.gui.QMenu;
import com.trolltech.qt.gui.QMenuBar;
import com.trolltech.qt.gui.QPalette;
import com.trolltech.qt.gui.QPixmap;
import com.trolltech.qt.gui.QPushButton;
import com.trolltech.qt.gui.QSizePolicy;
import com.trolltech.qt.gui.QStackedLayout;
import com.trolltech.qt.gui.QVBoxLayout;
import com.trolltech.qt.gui.QWidget;
import com.trolltech.qt.gui.QPalette.ColorRole;
import com.trolltech.qt.gui.QStackedLayout.StackingMode;
import com.trolltech.qt.svg.QSvgWidget;

import core.ChessAI;
import core.ChessBoard;
import core.RepetitionChecker;


/**
 * The GUI classfile which includes the main
 * @author Team Failboat
 * @version 0.5
 *
 */
 public class ChessGUI extends QMainWindow{
	 
	 /*Integers*/
	private static int 		chessboardSizeX = 900;
	private static int 		chessboardSizeY = 600;
	private int 			oldx = -1, oldy = -1;
	private int[][] 		oldMoves = null;
	private int 			blackGoneSize = 0, whiteGoneSize = 0;
	private int 			convertX, convertY;
	private static int 		gamemode;
		
	/*Strings*/
	private final static String 	IMAGEPATH="bin/GUI/img_icons/";
	private String 			hudcolor;
	private static String 	icontype;
	private String 			backgroundtype;
	private static String 	selectColor;
    private String 			fileSave = null;
	private String 			networkURL = "";
    
    /*Booleans*/
    private boolean 		clock=true;
	private boolean			gameOver;
	private boolean			countdown;
	private boolean			quick;
	private boolean			whiteAiEnabled=false;
	private boolean			blackAiEnabled=false;
	private boolean 		draw;
    
	/*Enumerators*/
	private ChessColor		localPlayer = null;
	
    /*Classes*/
	private Caretaker		caretaker;
	private ChessBoard 		board;
	private RepetitionChecker repCheck = new RepetitionChecker();
	private OptionGui 		options;
	private Settingshandler settings;
	private ClockGUI		whiteTimer = new ClockGUI(this, ChessColor.WHITE);
	private ClockGUI 		blackTimer = new ClockGUI(this, ChessColor.BLACK);

	
	/* Network-objects */
	private SocketConnection networkConnection;
	private ObjectInputStream networkIn;
	private ObjectOutputStream networkOut;
	private NetworkBoardReceiver receiver = null;

	/*QMenus*/
    private QMenu 			fileMenu;
    private QMenu 			settingsMenu;
    private QMenu			networkMenu;
    private QMenu 			helpMenu;
    
    /*QActions*/
    private QAction 		newAct;
    private QAction 		openAct;
    private QAction 		saveAct;
    private QAction			undoAct;
    private QAction 		exitAct;
	private QAction			clockAct;
    private QAction 		optionsAct;
    private QAction			hostAct;
    private QAction			connectAct;
    private QAction 		aboutAct;
    private QAction			aboutQtJambiAct;
    private QAction			whiteAiAct;
    private QAction			blackAiAct;
    
    /*QWidgets*/
    private QWidget 		chessBoardWidget;
    private QWidget 		eliminatedWidget;
    private QWidget 		convertBox;
    private QWidget 		mainWindow;
    private QWidget 		playTimer = new QWidget();

    /*Other Qs*/
    private QSizePolicy 	buttonSize;
    private QPushButton[][] buttons;
    private QPushButton[][] eliminated;
    private QHBoxLayout 	mlayout;
    private QVBoxLayout		rlayout;
    private QSvgWidget 		svg_background;
    private QGridLayout 	boardGrid = new QGridLayout();
    private QGridLayout 	eliminatedGrid = new QGridLayout();
    private QGridLayout 	rightTopLayout;
    
    /*Arraylists*/
	private ArrayList<Piece> 	blackGone;
	private ArrayList<Piece>	whiteGone;
	private ChessAI			aiBlack;
	private ChessAI			aiWhite;
    	
	/* String[][]s */
    private String[][] pieces_style;

    
    /**
     * Class that handles undo functionality
     * @author Failboat
     *
     */
    private class Caretaker{
    	ArrayList<Object> boardStates = new ArrayList<Object>();
    	
    	/**
    	 * Saves the board to a memento
    	 * @param mementoToSave
    	 */
    	public void saveState(Object mementoToSave){
    		boardStates.add(mementoToSave);
    	}
    	
    	/**
    	 * Method loads a board from memento
    	 * @return board
    	 */
    	public Object restoreLastState(){
    		if (boardStates.size() > 0){
	    		Object ret = boardStates.get(boardStates.size() - 1);
	    		boardStates.remove(boardStates.size() - 1);
	    		return ret;
    		}
    		return null;
    	}
    }
    
    /**
     * Creates the main window and adds content
     */
    public ChessGUI(){
    	board = new ChessBoard(0);
    	gameOver = false;
    	draw = false;
    	
    	/* Creates settingshandler and load settings from it */
    	settings = new Settingshandler();
    	loadSettings();
    	
    	/* Creates the style of all buttons on chessboard */
    	pieces_style = createStyleSheet();

    	/* Creates a menubar and sets it */
        QMenuBar menuBar = new QMenuBar();
        setMenuBar(menuBar);
        
        /* Creating ChessBoardWidget */
        createChessBoard();
        
        /* Creating undo-functionality */
        caretaker = new Caretaker();
        
        /* Creating playTimer 
         * If enabled, creates the clock for both players
         */
        createPlayTimer();
        
        /* Creating EliminatedWidget 
         * A widget that contains beaten pieces
         */
        createEliminatedField();
        
        /* Main frame */
        mainWindow = new QWidget();
        
        /* Background of chessboard in svg to be scalable */
        svg_background = new QSvgWidget();
        svg_background.load(""+IMAGEPATH+""+"background"+backgroundtype+".svg");

        /* Stacks the chessboard on top of the background */
        QStackedLayout stackLeft = new QStackedLayout();
        stackLeft.setStackingMode(StackingMode.StackAll);
        stackLeft.addWidget(svg_background);
        stackLeft.addWidget(chessBoardWidget);
        
        /* A layout for side by side QWidgets */
        mlayout = new QHBoxLayout(mainWindow); //Horizontal layout
        mlayout.addLayout(stackLeft,(int) (chessboardSizeX/1.5));//Size of chessboard is 2/3 of total width
        
        /* Split right side of mlayout horizontally */
        rlayout = new QVBoxLayout(); //Vertical layout
        rlayout.addWidget(playTimer);
        rlayout.addWidget(eliminatedWidget);
        mlayout.addLayout(rlayout,(int) (chessboardSizeX/3));//Size of right of chessboard is 1/3 of total width
        
        /* Set main frame as central widget */
        setCentralWidget(mainWindow);
        
        /* Creates menues, their actions and the status bar */
        createActions();
        
        createMenus();
        createStatusBar();
        
        /* Set loaded settings */
    	setSettings();
    	
    	newGame();
    }
    


	/**
     * 
     * String[*][0] = Transparent<br />
     * String[*][1] = Blue(selected)<br />
     * String[*][2] = Red(piece path)<br />
     * String[0][*] = Empty cell<br />
     * String[1-6][*] = White Pieces<br />
     * String[7-12][*] = Black Pieces
     * 
     * @return String[][] with stylesheet for all buttons
     */
    private static String[][] createStyleSheet() {
    	String[][] styleSheet = {
    	    /*
    	     *[what piece][0=transparent bg, 1=blue bg, 2=red bg]
    	     *
    	     * Empty cell [0]
    	     * 
    	     */
    	    {
    	    ("QPushButton{border-image: url("+IMAGEPATH+"transparent_1px.png); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
    	    ("QPushButton{border-image: url("+IMAGEPATH+"transparent_1px.png); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
    	    ("QPushButton{border-image: url("+IMAGEPATH+"transparent_1px.png); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
    	    },
    	    
    		/* White pieces[1]-[6] */
    	    {
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	    	},{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	    	},{
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	        ("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"w_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        }, 
	    	
	    	/* Black pieces not selected [7]-[12] */
	        { 
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_pawn.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}"),
	        },{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	       	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_knight.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	    	},{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_bishop.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_rook.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_queen.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        },{
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+"transparent_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor+"blue_1px.png)}"),
	    	("QPushButton{border-image: url("+IMAGEPATH+"pieces/"+icontype+"b_king.png); color: rgba(0, 0, 0, 0%); background-image: url("+IMAGEPATH+selectColor +"red_1px.png)}")
	        }
    	};
    	return styleSheet;
	}

	/**
     * Method to collect all that has to do with chessBoardWidget
     */
    private void createChessBoard(){
    	
    	/* Create chessboard as widget */
        chessBoardWidget = new QWidget();
    	buttonSize = new QSizePolicy(QSizePolicy.Policy.Expanding,QSizePolicy.Policy.Expanding); //Autoresize buttons
        boardGrid.setSpacing(0); //Space between buttons is 0
        boardGrid.setContentsMargins(3, 3, 3, 3);//Margins, 3 seems to be best concering alignment of background compared to selection
        chessBoardWidget.setLayout(boardGrid);
        
    	/* Create table with QPushButtons */
        buttons = new QPushButton[8][8];
        
        /* Create the chessboard buttons with listeners */
        for(int i=0; i<buttons.length;i++){
        	for(int j=0; j<buttons[0].length;j++){
        		buttons[i][j] = new QPushButton();
        		buttons[i][j].setStyleSheet(pieces_style[0][0]);
        		buttons[i][j].setSizePolicy(buttonSize);
        		buttons[i][j].clicked.connect(this,"chessListen"+i+j+"()"); //Creating listeners here, cause each button needs their own listener to find the source
        	}
        }
               
        /* Add buttons to board */
        for(int i=0; i<buttons.length;i++){
        	for(int j=0; j<buttons[1].length;j++){
        		boardGrid.addWidget(buttons[i][j],j,i);
        	}
        }
        
        /* Updates the graphics on the board */
        updateBoard();
    }
    
    /**
     * Method that creates the eliminated space in the main window.
     * Using QPushButton to display the pictures, because it is convenient when resizing.
     */
    private void createEliminatedField(){
    	eliminatedWidget = new QWidget();
    	eliminatedWidget.setLayout(eliminatedGrid);
    	eliminatedGrid.setSpacing(0);
    	eliminatedGrid.setContentsMargins(4, 4, 4, 4);
    	eliminated = new QPushButton[4][8];
        for(int i=0; i<eliminated.length;i++){
        	for(int j=0; j<eliminated[0].length;j++){
        		eliminated[i][j] = new QPushButton();
        		eliminated[i][j].setStyleSheet(pieces_style[0][0]);
        		eliminated[i][j].setSizePolicy(buttonSize);
        		eliminated[i][j].adjustSize();
        	}
        }
        for(int i=0; i<eliminated.length;i++){
        	for(int j=0; j<eliminated[1].length;j++){
        		eliminatedGrid.addWidget(eliminated[i][j],j,i);
        	}
        }
    }

    /**
     * Method that creates the timer for players
     */
    private void createPlayTimer() {
    	playTimer = new QWidget();
    	rightTopLayout = new QGridLayout();    	
    	QLabel whiteLabel = new QLabel("White Player");
    	QLabel blackLabel = new QLabel("Black Player");
    	QFont labelFont = new QFont();
    	
    	labelFont.setBold(true);
    	labelFont.setPointSize(12);
    	whiteLabel.setAlignment(AlignmentFlag.AlignHCenter);
    	blackLabel.setAlignment(AlignmentFlag.AlignHCenter);
    	whiteLabel.setFont(labelFont);
    	blackLabel.setFont(labelFont);
    	
    	rightTopLayout.addWidget(whiteLabel, 0, 0);
    	rightTopLayout.addWidget(blackLabel, 0, 1);
    	rightTopLayout.addWidget(whiteTimer, 1, 0);
    	rightTopLayout.addWidget(blackTimer, 1, 1);
    	
    	playTimer.setLayout(rightTopLayout);
    	blackTimer.runTimer(false, false);
    }
    	
    /**
     * Method to switch between the clocks
     */
    private void switchClock(boolean changeTurn){
    	if(board.getTurn()== ChessColor.BLACK){
    		whiteTimer.runTimer(false,changeTurn);
    		blackTimer.runTimer(true,changeTurn);
    		whiteTimer.refreshClock();
    	}else{
    		whiteTimer.runTimer(true,changeTurn);
    		blackTimer.runTimer(false,changeTurn);
    		blackTimer.refreshClock();
    	}
    }
    
    /**
     * Method to stop the clocks when for example patt or checkmate
     */
    void stopClock(){
    	whiteTimer.runTimer(false,false);
    	blackTimer.runTimer(false,false);
    }
    	
    /**
     * Method to reset the clocks
     */
    private void resetClock(){
    	whiteTimer.getTimer().setCountdown(countdown, quick);
    	blackTimer.getTimer().setCountdown(countdown, quick);
    	whiteTimer.getTimer().resetTimer();
    	blackTimer.getTimer().resetTimer();
    	refreshClock();
    }
    
    /**
     * Method to resume clocks for example after optionsGUI has been closed
     */
    void resumeClock(){
    	if(board.getTurn()== ChessColor.BLACK){
    		whiteTimer.runTimer(false,false);
    		blackTimer.runTimer(true, false);
    	}else{
    		whiteTimer.runTimer(true,false);
    		blackTimer.runTimer(false,false);
    	}
    }
    
    /**
     * Method to refresh the clocks, for example after loading a game
     */
    private void refreshClock(){
    	whiteTimer.refreshClock();
    	blackTimer.refreshClock();
    	resumeClock();
    }
		
    /**
     * Returns if clock is used or not
	 * @return clock
	 * (boolean)
	 */
	boolean isClock() {
		return clock;
	}
    
	@SuppressWarnings("unused")
	private void showClock(){
		if(playTimer.isVisible()){
			playTimer.hide();
			clockAct.setIcon(new QIcon(IMAGEPATH + "/transparent_1px.png"));
		}else{
			playTimer.show();
			clockAct.setIcon(new QIcon(IMAGEPATH + "/check.png"));
		}
	}
	
    /**
     * Method to refresh/load settings from the settings file using the Settingshandler
     */
    void loadSettings(){    	
    	settings.loadSettings();
		hudcolor = settings.getHudcolor();
		icontype = settings.getIcontype();
		backgroundtype = settings.getBackgroundtype();
		chessboardSizeX = settings.getChessboardSizeX();
		selectColor = settings.getSelectcolor();
		gamemode = settings.getGameMode();
		countdown = settings.getCountDown();
		quick = settings.getQuick();
		clock = settings.getClock();
    }
    
    /**
     * Updates the settings loaded in loadSettings()
     */
    void setSettings(){
		setHUDColor(hudcolor);
		updateBoard();
		svg_background.load(""+IMAGEPATH+""+"background"+backgroundtype+".svg");
		setBoardSize(chessboardSizeX);
		clearEliminated();
		loadEliminated();
    }
    
    /**
     * Method to refresh all pieces on the the board. Calls clear and loadeliminated.
     */
    void updateBoard() {
    	pieces_style = createStyleSheet();
    	for(int i=0; i<buttons.length;i++){
        	for(int j=0; j<buttons[0].length;j++){
        		buttons[i][j].setStyleSheet(findStyleSheet(board.getPiece(i, j), 0));
        	}
    	}
    	clearEliminated();
    	loadEliminated();
	}
    
    
    /**
     * Method to set size of the application, takes width of the application as argument and sets height to correct aspect
     * @param int width
     */
   private void setBoardSize(int width){
    	chessboardSizeX = width;
    	chessboardSizeY = (int)(width/1.5);
    	this.setMaximumSize(chessboardSizeX, chessboardSizeY);
        this.setMinimumSize(chessboardSizeX, chessboardSizeY);
        this.resize(chessboardSizeX, chessboardSizeY);
    }
    
    /**
     * Sets the background color of the whole application
     * @param QColor color
     */
    private void setHUDColor(String colors){
    	   String[] color = new String[3];
    	   color = colors.split("\\,");
    	   QPalette pal = new QPalette();
    	   pal.setColor(ColorRole.Window, new QColor(Integer.parseInt(color[0]),Integer.parseInt(color[1]),Integer.parseInt(color[2]),Integer.parseInt(color[3])));
    	   this.setPalette(pal);
    	   
    }
    
    /**
     * Method that adds content and listeners to top menu
     */
    private void createActions(){
    	/* New game */
        newAct = new QAction(new QIcon(IMAGEPATH + "/new.png"), tr("&New Game"), this);
        newAct.setShortcut(new QKeySequence(tr("Ctrl+N")));
        newAct.setStatusTip(tr("Create a new game"));
        newAct.triggered.connect(this, "newGame()");

        /* Load game */
        openAct = new QAction(new QIcon(IMAGEPATH + "/load.png"), tr("&Load Saved Game"), this);
        openAct.setShortcut(tr("Ctrl+L"));
        openAct.setStatusTip(tr("Open a game"));
        openAct.triggered.connect(this, "load()");

        /* Save game */
        saveAct = new QAction(new QIcon(IMAGEPATH + "/save.png"), tr("&Save Game"), this);
        saveAct.setShortcut(tr("Ctrl+S"));
        saveAct.setStatusTip(tr("Save the game"));
        saveAct.triggered.connect(this, "save()");
        
        /* Undo move */
        undoAct = new QAction(new QIcon(IMAGEPATH + "/undo.png"), tr("&Undo Move"), this);
        undoAct.setShortcut(tr("Ctrl+Z"));
        undoAct.setStatusTip(tr("Undo your last move"));
        undoAct.triggered.connect(this, "undo()");

        /* Exit application */
        exitAct = new QAction(new QIcon(IMAGEPATH + "/exit.png"), tr("&Exit"), this);
        exitAct.setShortcut(tr("Ctrl+Q"));
        exitAct.setStatusTip(tr("Exit the application"));
        exitAct.triggered.connect(this, "close()");

        /* Enable/Disable clock */
        clockAct = new QAction(new QIcon(IMAGEPATH + "/check.png"),tr("Show/Hide Clock"), this);
        clockAct.setStatusTip(tr("Show/Hide Clock"));
        clockAct.triggered.connect(this, "showClock()");
        
        /* Options */
        optionsAct = new QAction(new QIcon(IMAGEPATH + "/options.png"), tr("&Options"), this);
        optionsAct.setShortcut(tr("Ctrl+O"));
        optionsAct.setStatusTip(tr("Options"));
        optionsAct.triggered.connect(this, "options()");
        
        /* Enable/Disable AI */
        whiteAiAct = new QAction(new QIcon(IMAGEPATH + "/transparent_1px.png"), tr("White AI"), this);
        blackAiAct = new QAction(new QIcon(IMAGEPATH + "/transparent_1px.png"), tr("Black AI"), this);
        whiteAiAct.setStatusTip(tr("Enable/Disable AI"));
        blackAiAct.setStatusTip(tr("Enable/Disable AI"));
        whiteAiAct.triggered.connect(this, "whiteAi()");
        blackAiAct.triggered.connect(this, "blackAi()");
        
        /* Host network game */
        hostAct = new QAction(new QIcon(IMAGEPATH + "/host.png"), tr("&Host network game"), this);
        hostAct.setStatusTip(tr("Starts hosting a network game"));
        hostAct.triggered.connect(this, "hostGame()");
        
        /* Connect to a network game */
        connectAct = new QAction(new QIcon(IMAGEPATH + "/connect.png"), tr("&Connect to a network game"), this);
        connectAct.setStatusTip(tr("Shows a window with available games and lets you connect to one"));
        connectAct.triggered.connect(this, "showConnectDialog()");
        
        /* About the game */
        aboutAct = new QAction(new QIcon(IMAGEPATH + "/about.png"), tr("&About"), this);
        aboutAct.setStatusTip(tr("Show the application's About box"));
        aboutAct.triggered.connect(this, "about()");
        aboutAct.triggered.connect(this, "stopClock()");

        /* About QT */
        aboutQtJambiAct = new QAction(new QIcon(IMAGEPATH +"/qt-logo.png"),tr("About &Qt Jambi"), this);
        aboutQtJambiAct.setStatusTip(tr("Show the Qt Jambi library's About box"));
        aboutQtJambiAct.triggered.connect(QApplication.instance(), "aboutQtJambi()");
    }

    /**
     * Method that creates the top menu
     */
    private void createMenus(){
    	
    	/* Create file menu */
        fileMenu = menuBar().addMenu(tr("&File"));
        fileMenu.addAction(newAct);
        fileMenu.addAction(openAct);
        fileMenu.addAction(saveAct);
        fileMenu.addSeparator();
        fileMenu.addAction(undoAct);
        fileMenu.addSeparator();
        fileMenu.addAction(exitAct);

        /* Create settings menu */
        settingsMenu = menuBar().addMenu(tr("&Settings"));
        settingsMenu.addAction(clockAct);
        settingsMenu.addAction(optionsAct);
        settingsMenu.addSeparator();
        settingsMenu.addAction(blackAiAct);
		settingsMenu.addAction(whiteAiAct);
        
        /* Creates network menu */
        networkMenu = menuBar().addMenu(tr("Network game"));
        networkMenu.addAction(hostAct);
        networkMenu.addAction(connectAct);

        /* Create help menu */
        helpMenu = menuBar().addMenu(tr("&Help"));
        helpMenu.addAction(aboutAct);
        helpMenu.addSeparator();
        helpMenu.addAction(aboutQtJambiAct);
    }
    
    /**
     * Method that handles what happens when you press New Game in the File menu
     */
   void newGame(){
    	loadSettings();
    	setSettings();
    	whiteTimer.getTimer().setCountdown(countdown, quick);
    	blackTimer.getTimer().setCountdown(countdown, quick);
    	board = new ChessBoard(gamemode);
    	if(clock){
    		resetClock();
    		playTimer.show();
    		clockAct.setIcon(new QIcon(IMAGEPATH + "/check.png"));
    	}else{
    		resetClock();
    		stopClock();
    		playTimer.hide();
			clockAct.setIcon(new QIcon(IMAGEPATH + "/transparent_1px.png"));
    	}
    	if(whiteAiEnabled){
    		aiWhite = new ChessAI(board, ChessColor.WHITE, this);
    		aiWhite.start();
    	}
    	if(blackAiEnabled){
    		aiBlack = new ChessAI(board, ChessColor.BLACK, this);
    		aiBlack.start();
    	}
    	if(blackAiEnabled && whiteAiEnabled){
    		gameOver = true;
    	}
    	gameOver = false;
    	if(networkConnection == null){
    		localPlayer = null;
    	}
    	draw = false;
    	blackGoneSize = 0;
    	whiteGoneSize = 0;
    	oldx = -1;
    	oldy = -1;
    	oldMoves = null;
    	clearEliminated();
    	updateBoard();
    }
    
    /**
     * Method to get the home directory of a OS
     * @return String OS home directory
     */
    private String getHomeDirectory(){
    	
    	String os = java.lang.System.getProperty("os.name").toLowerCase().trim();
    	System.out.println(os);
    	
    	if(os.contains("windows")){
			QSettings settings = new QSettings("Microsoft", "Windows");
		    settings.beginGroup("CurrentVersion/Explorer/Shell Folders");
		    return settings.value("Personal").toString();
    	
    	}else if(os.contains("linux")){
    		return (System.getProperty("user.home"));
    	
    	}else if(os.contains("mac")){
    		return (System.getProperty("user.home")); // This dows not work with QFileDialog as Mac OS X overrides
    	}
    	return null;
    }
    
    /**
     * Method that handles what happens when you press Load in the File menu
     */
    @SuppressWarnings("unused")
	private void load(){
    	try{
        	blackGoneSize = 0;
        	whiteGoneSize = 0;
        	oldx = -1;
        	oldy = -1;
        	oldMoves = null;
    		String fileName = QFileDialog.getOpenFileName(this, "Open Save", getHomeDirectory(),new QFileDialog.Filter("*.sav"));
    		ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
    		board = (ChessBoard) in.readObject();
    		whiteTimer.setTimer((ClockCore) in.readObject());
    		blackTimer.setTimer((ClockCore) in.readObject());
    		refreshClock();
    		clearEliminated();
    		updateBoard();
    		loadEliminated();
    		statusBar().showMessage("Game Loaded!");
    		checkStaleMateOnLoad();
    	}catch (Exception e) {
    		statusBar().showMessage("Game Load Failed cause of "+e);
		}
    }
    
    /**
     * Method that handles what happens when you press Save in the File menu
     */
    @SuppressWarnings("unused")
	private void save(){
    	try{
    		if(fileSave == null || !fileSave.contains(".sav")){
    			fileSave = QFileDialog.getSaveFileName(this, "Save Game", getHomeDirectory(),new QFileDialog.Filter("*.sav"));
    		}
    		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileSave));
    		out.writeObject(board);
	    	out.writeObject(whiteTimer.getTimer());
	    	out.writeObject(blackTimer.getTimer());
			out.close();
			statusBar().showMessage("Game Saved!");
    	}catch (Exception e) {
    		statusBar().showMessage("Game Save Failed cause of "+e);
		} 	
    }
    
    /**
     * Method that loads a saved board from the caretaker, and sends it back to
     * the originator.
     */
    @SuppressWarnings("unused")
	private void undo(){
    	Object tempMemento = caretaker.restoreLastState();
    	if (tempMemento != null){
    		board.restoreFromMemento(tempMemento);
    		repCheck.removeLastEntry();
    		oldMoves = null;
        	updateBoard();
        	clearEliminated();
        	loadEliminated();
        	whiteGoneSize = whiteGone.size() - 1;
        	blackGoneSize = blackGone.size() - 1;
        	if (whiteGoneSize < 0) { whiteGoneSize = 0; }
        	if (blackGoneSize < 0) { blackGoneSize = 0; }
        	checkStaleMateOnLoad();
        	switchClock(false);
    	}	
    }
    
    
    void setNetworkURL(String url){
    	networkURL = url;
    }
    
    /**
     * Method that sets the board. Made for NetworkBoardReceiver.
     * And invokes updateboard for external threads.
     * @param board
     */
    void setBoard(ChessBoard board){
    	if(board.getTurn() != localPlayer){
    		try{
    			Thread.sleep(1000);
    		}catch (Exception e){
    			// does noting.
    		}
    		receiveBoard();
    		return;
    	}
    	this.board = board;
    	
    	/* Creates threaded object to update GUI without getting nasty exceptions */
        QApplication.invokeLater(new Runnable() {
            public void run() {
                synchronized (receiver) {
                   updateBoard();
                   doChecks();
                   statusBar().showMessage(tr("Your turn"));
                }
            }
        });
    }
    
    
    /**
     * A Method that is used by the ai thread to update the board and check if game is over.
     * @param updater
     */
    public void fireBoardUpdate(final Object updater){
    	QApplication.invokeLater(new Runnable() {
            public void run() {
                synchronized (updater) {
                	doChecks();
                	updateBoard();
                	if(board.getTurn() == ChessColor.BLACK && blackAiEnabled){
                		synchronized (aiBlack) {
                			aiBlack.notify();
                		}
                	}else if(board.getTurn() == ChessColor.WHITE && whiteAiEnabled){
                		synchronized (aiWhite) {
                			aiWhite.notify();
                		}
                	}
                	
                }
            }
        });
    }
    
    
    /**
     * Method that performs checks to see if the game has ended. If so calling endGame.
     */
    @SuppressWarnings("deprecation")
	private void doChecks(){
    	if(board.isStaleMate(board.getTurn())){
			gameOver = true;
			if(clock){
				stopClock();
			}
			/* Sets apropriate game over message */
			if(board.isCheck(board.findPiece(board.getTurn(), "king"))){
				statusBar().showMessage(tr("" + board.getTurn() + " is checkmate!"));
			}else{
				statusBar().showMessage(tr("" + board.getTurn() + " is stalemate! (No legal moves, but not in check)"));
			}
			if(blackAiEnabled){
				aiBlack.stop();
			}
			if(whiteAiEnabled){
				aiWhite.stop();
			}
			endGame(board.getTurn());
		}
		
		/* Checks for repetion. If so, ending the game */
		else if (repCheck.checkForRepetition(board)){ 
			gameOver = true;
			draw = true;
			statusBar().showMessage(tr("Game drawn due to repetion."));
			if(clock){
				stopClock();
			}
			if(blackAiEnabled){
				aiBlack.stop();
			}
			if(whiteAiEnabled){
				aiWhite.stop();
			}
			endGame(board.getTurn());
		}else{ //The game is still running.
			if(clock){
				switchClock(true); //Switch clock if turn has ended and clock is enabled
			}
		}
    	saveBoardState();
    }
    
    /**
     * Method that gets the board in play
     * @return board
     */
    @Deprecated
    ChessBoard getBoard(){
    	return board;
    }
    
    /**
     * Method that saves the state of the board to a Memento object.
     */
    private void saveBoardState(){
    	caretaker.saveState(board.saveToMemento());	
    }
    
    
    /**
     * Hosts a network game.
     */
    @SuppressWarnings("unused")
    private void hostGame(){
    	networkConnection = new SocketConnection("not used for serverside", true); //Creates socket.
    	statusBar().showMessage(tr("Starting network game. Waiting for incoming connections"));
    	
    	/* Tries to establish connection */
    	if(networkConnection.getConnection()){
    		statusBar().showMessage(tr("Connection established. Opening datastreams."));
    		networkOut = networkConnection.getOutput();
    		networkIn = networkConnection.getInput();
    		receiver = new NetworkBoardReceiver(networkIn, networkConnection, this);
    		receiver.start();
    		
    		if(networkIn == null || networkOut == null){ //If something goes wrong
    			localPlayer = null;
    			statusBar().showMessage(tr("Connection failed. Could not open datastreams."));
    		}else { //Or if worked
    			statusBar().showMessage(tr("Connected to opponent. Exchanging data."));
    			newGame();
    			localPlayer = ChessColor.WHITE; //sets the localplayer value so that player cannot lock other pieces.
    		}
    	}else {
    		statusBar().showMessage(tr("Connection failed. Could not connect."));
    	}
    }
    
    
    /**
     * Connects to a server. Shows message dialog.
     */
    @SuppressWarnings("unused")
	private void showConnectDialog(){
    	NetworkGUI networkGUI = new NetworkGUI(this);
    	networkGUI.setModal(true);
    	networkGUI.setWindowTitle("Connect to host");
    	networkGUI.setWindowIcon(new QIcon(IMAGEPATH+"pieces/00b_king.png"));
    	networkGUI.show();
    }
    
    
    /**
     * Performs the connection to server specified in the showConnectDialog window.
     */
    void connectToGame(){
    	/*
    	 * See HostGame for details. Basically same procedure.
    	 */
    	networkConnection = new SocketConnection(networkURL, false);
    	statusBar().showMessage(tr("Connecting to host."));
    	if(networkConnection.getConnection()){
    		statusBar().showMessage(tr("Connection established. Opening datastreams."));
    		networkOut = networkConnection.getOutput();
    		networkIn = networkConnection.getInput();
    		receiver = new NetworkBoardReceiver(networkIn, networkConnection, this);
    		receiver.start();
    		if(networkIn == null || networkOut == null){
    			localPlayer = null;
    			statusBar().showMessage(tr("Connection failed. Could not open datastreams."));
    		}else {
    			statusBar().showMessage(tr("Connected to opponent and server. Receiving data."));
    			newGame();
    			localPlayer = ChessColor.BLACK;
    		}
    	}else {
    		statusBar().showMessage(tr("Connection failed. Could not find host."));
    	}
    }
    
    
    /**
     * Sends the chessBoard over an open networkConnection
     */
    private void sendBoard(){
    	if(networkConnection != null && networkConnection.getConnection()){
	    	try {
				networkOut.writeObject(board);
				networkOut.flush(); //Flushes after send. Gets rid of bad bugs.
				statusBar().showMessage(tr("Data sent"));
				updateBoard();
				statusBar().showMessage(tr("Waiting for opponent's move")); 
			} catch (IOException e) {
					e.printStackTrace();
					networkOut = null;
					networkIn = null;
					localPlayer = null;
					networkConnection.closeAll();
					networkConnection = null;
					statusBar().showMessage(tr("Connection to opponent lost"));
			}
    	}
    }
    
    /**
     * Method that notifies the receiver thread and sets appropriate waiting message.
     * Networking only 
     */
    private void receiveBoard(){
    	if(networkConnection != null && networkConnection.getConnection()){
    		
    		/* Notifies the receiver-thread */
    		synchronized (receiver) {  			
			if(receiver.getState() == State.WAITING){
					receiver.notify();
				}
			}
    	}
    }
    
    /**
     * Method that activates/deactivates AI control on white pieces.
     */
    @SuppressWarnings({ "deprecation", "unused" })
	private void whiteAi(){
		if(whiteAiEnabled){
			//disable
			aiWhite.stop();
			aiWhite = null;
			whiteAiEnabled = false;
			whiteAiAct.setIcon(new QIcon(IMAGEPATH + "/transparent_1px.png"));
			if(blackAiEnabled){
				localPlayer = ChessColor.WHITE;
				gameOver = false;
			}else{
				localPlayer = null;
			}
		}else{
			aiWhite = new ChessAI(board, ChessColor.WHITE, this);
			aiWhite.start();
			whiteAiEnabled = true;
			whiteAiAct.setIcon(new QIcon(IMAGEPATH + "/check.png"));
			if(blackAiEnabled){
				gameOver = true;
				
			}else{
				localPlayer = ChessColor.BLACK;
			}
		}
    }
    
    /**
     * Method that activates/deactivates AI control on black pieces.
     */
    @SuppressWarnings({ "deprecation", "unused" })
	private void blackAi(){
		if(blackAiEnabled){
			aiBlack.stop();
			aiBlack = null;
			blackAiEnabled = false;
			blackAiAct.setIcon(new QIcon(IMAGEPATH + "/transparent_1px.png"));
			if(whiteAiEnabled){
				localPlayer = ChessColor.BLACK;
				gameOver = false;
			}else{
				localPlayer = null;
			}
		}else{
			aiBlack = new ChessAI(board, ChessColor.BLACK, this);
			aiBlack.start();
			blackAiEnabled = true;
			blackAiAct.setIcon(new QIcon(IMAGEPATH + "/check.png"));
			if(whiteAiEnabled){
				gameOver = true;
				
			}else{
				localPlayer = ChessColor.WHITE;
			}
		}
    }
    
    
    /**
     * Method that handles what happens when you press quit the game
     */
	protected void closeEvent(QCloseEvent event){
		if (networkConnection != null){
			networkConnection.closeAll();
		}
    }
    
	
    /**
     * Method that handles what happens when you press Options in the Settings menu
     */
    @SuppressWarnings("unused")
	private void options(){
    	options = new OptionGui(this);
    	options.show();
    }
    
    
    /**
     * Method that handles what happens when you press About in the Help menu
     */
    @SuppressWarnings("unused")
	private void about(){
    	QWidget about = new QWidget();
    	QHBoxLayout aboutLayout = new QHBoxLayout(about);
    	QVBoxLayout aboutVLayout = new QVBoxLayout();
    	QLabel aboutLabel = new QLabel("Chessboat 2010:\n\nThis chess application was made" +
    									" by\nthe awesome Team Failboat.\n\nCopyleft 2010");
    	QPixmap aboutPix = new QPixmap(IMAGEPATH+"failboat.png");
    	QLabel aboutLabelPix = new QLabel();
    	QPushButton aboutButton = new QPushButton("Close");
    	aboutButton.clicked.connect(about, "close()");
    	aboutButton.clicked.connect(this,"resumeClock()");
    	aboutButton.setFixedSize(50, 25);
    	aboutPix = aboutPix.scaled((int) (480/1.5), (int) (320/1.5));
    	aboutLabelPix.setPixmap(aboutPix);
    	aboutVLayout.addWidget(aboutLabel);
    	aboutVLayout.addWidget(aboutButton);
    	aboutVLayout.setAlignment(aboutButton, Qt.AlignmentFlag.AlignHCenter);
    	aboutLayout.addLayout(aboutVLayout);
    	aboutLayout.addWidget(aboutLabelPix);
    	about.setWindowTitle("About Chess");
    	about.setWindowIcon(new QIcon(IMAGEPATH+"about.png"));
    	about.setWindowModality(Qt.WindowModality.ApplicationModal);
    	about.show();
    }
    
    /**
     * Method that creates a status bar
     */
    private void createStatusBar(){
        statusBar().showMessage(tr("Ready"));
    }
    

    /**
     * 
     * Buttonlistener that replaces a pawn that has made it across the board
     * with a Knight
     */
    @SuppressWarnings("unused")
	private void pawnPromoter0(){
    	board.setPiece(new Knight(board.getPiece(convertX, convertY).getPiecenr(),convertX,convertY
								,board.getPiece(convertX, convertY).getColor()), convertX, convertY);
    	convertBox.close();
    	updateBoard();
    }
    
    /**
     * Buttonlistener that replaces a pawn that has made it across the board
     * with a Bishop
     */
    @SuppressWarnings("unused")
	private void pawnPromoter1(){
    	board.setPiece(new Bishop(board.getPiece(convertX, convertY).getPiecenr(),convertX,convertY
								,board.getPiece(convertX, convertY).getColor()), convertX, convertY);
    	convertBox.close();
    	updateBoard();
    }
    
    /**
     * Buttonlistener that replaces a pawn that has made it across the board
     * with a Rook
     */
    @SuppressWarnings("unused")
	private void pawnPromoter2(){
    	board.setPiece(new Rook(board.getPiece(convertX, convertY).getPiecenr(),convertX,convertY
								,board.getPiece(convertX, convertY).getColor()), convertX, convertY);
    	convertBox.close();
    	updateBoard();
    }
    
    /**
     * Buttonlistener that replaces a pawn that has made it across the board
     * with a Queen
     */
    @SuppressWarnings("unused")
	private void pawnPromoter3(){
    	board.setPiece(new Queen(board.getPiece(convertX, convertY).getPiecenr(),convertX,convertY
								,board.getPiece(convertX, convertY).getColor()), convertX, convertY);
    	convertBox.close();
    	updateBoard();
    }

    /**
     * Method for handling the button actions
     * @param String nr(gets number from the buttons). Format "xy"
     */
    private void boardButtonListener(String nr){
    	if ((!gameOver) 
    		&& (((localPlayer != null) && (localPlayer == board.getTurn())) 
    			 || (localPlayer == null))){
    	
	    	int x = Integer.parseInt(""+nr.charAt(0));
	    	int y = Integer.parseInt(""+nr.charAt(1));
	    	
	    	//Checks if new piece of same color is chosen or not. Enters if new piece not chosen
	    	if((oldMoves != null) && ((board.getPiece(x, y) == null) 
	    		|| !(board.getPiece(oldx, oldy).getColor().equals(board.getPiece(x, y).getColor())))){
	    		saveBoardState();
	    		for(int[] move : oldMoves){
	    			if(move[0] == x && move[1] == y){
	    				if (!board.movePiece(board.getPiece(oldx, oldy), move[0], move[1])){
	    					
	    					//Setting message if failed move reported
	    					if (board.isCheck(board.findPiece(board.getPiece(oldx, oldy).getColor(), "king"))){
	                            statusBar().showMessage(tr("Move failed (" + board.getPiece(oldx, oldy).getColor() + ": "
	                                                       +((char)(oldx+65))+(8-oldy)+" to " +((char)(x+65))+(8-y)) 
	                                                       + "). You are checked!");
	    					}else if(board.isCheck(move[0], move[1], board.getTurn())){
	    						statusBar().showMessage(tr("Move failed (" + board.getPiece(oldx, oldy).getColor() + ": "
	                                    +((char)(oldx+65))+(8-oldy)+" to " +((char)(x+65))+(8-y)) 
	                                    + "). You cannot put yourself in check!");
	    					}else {
	                            statusBar().showMessage(tr("Move failed (" + board.getPiece(oldx, oldy).getColor() + ": "
	                                                       +((char)(oldx+65))+(8-oldy)+" to " +((char)(x+65))+(8-y)) 
	                                                       + "). You cannot put yourself in check!");
	                    }
	    				}else{
	
	    					//Setting success message
	    					statusBar().showMessage(tr("" + board.getPiece(x, y).getColor() + ": "
	    												+((char)(oldx+65))+(8-oldy)+" to " +((char)(x+65))+(8-y)));
	    					
	    					//Updating fields
	    					buttons[oldx][oldy].setStyleSheet(findStyleSheet(board.getPiece(oldx, oldy), 0));
	    					buttons[x][y].setStyleSheet(findStyleSheet(board.getPiece(x, y), 0));
	    					
	    					//Remove old visual markings
	    					updateBoard();
	    					oldMoves = null;
	    					checkEliminated();
	    					
	    					//checks if the piece is a pawn and has made it across the board.
	    					if(board.getPiece(x, y) instanceof pieces.Pawn && (y == 7 || y == 0)){
	        					promotePawn(board.getPiece(x, y));
	    					}
	    					
	    					/* Checks if the game has ended in stalemate or checkmate */
	    					if(board.isStaleMate(board.getTurn())){
	    						gameOver = true;
	    						endGame(board.getTurn());
	    						if(clock){
	    							stopClock();
	    						}
	    						
	    						/* Sets apropriate game over message */
	    						if(board.isCheck(board.findPiece(board.getTurn(), "king"))){
	    							statusBar().showMessage(tr("" + board.getTurn() + " is checkmate!"));
	    						}else{
	    							statusBar().showMessage(tr("" + board.getTurn() + " is stalemate! (No legal moves, but not in check)"));
	    						}
	    					}
	    					
	    					/* Checks for repetion. If so, ending the game */
	    					else if (repCheck.checkForRepetition(board)){
	    						gameOver = true;
	    						draw = true;
	    						endGame(board.getTurn());
	    						statusBar().showMessage(tr("Game drawn due to repetion."));
	    						if(clock){
	    							stopClock();
	    						}
	    					}else{ //The game is still running.
	    						if(clock){
	    							switchClock(true); //Switch clock if turn has ended and clock is enabled
	    						}
	    					}
	    				}
	    			}
	    			/* If network game - communicate with the other player */
	            	if(localPlayer != null && networkConnection != null){
	        			if (board.getTurn() != localPlayer){
	        				sendBoard();
	        				receiveBoard();
	        			}
	        		}
	    		}
	    	}else {
	    		
	    		/*If this is not a move-selection*/
	    		switchPiece(x,y);
	    	}
    	}
    	
    	if(blackAiEnabled && board.getTurn() == ChessColor.BLACK){
    		aiBlack.setBoard(board);
    		synchronized (aiBlack) {
				aiBlack.notify();
			}
    	}else if(whiteAiEnabled && board.getTurn() == ChessColor.WHITE){
    		aiWhite.setBoard(board);
    		synchronized (aiWhite) {
				aiWhite.notify();
			}
    	}
    }
    
    /**
     * Method to mark a selected piece
     * @param x
     * @param y
     */
    private void switchPiece(int x, int y){
    	
    	// Finds out whats on the position that is clicked
    	Piece clicked = board.getPiece(x, y);
    	
    	//Checks if it's the chosen colors turn. Returns if not
    	if((clicked == null) || (!clicked.getColor().equals(board.getTurn()))) { 
    		return; 
    	}
    	
    	//Gets stylesheet for clicked piece (marking the field blue)
    	String styleSheet = findStyleSheet(clicked, 1);
    	
    	//removes old fields if present
    	removeOldMarkedFields();
    	
    	/* Chooses correct icon and turn it blue, then sets statusbar message */  
    	buttons[x][y].setStyleSheet(styleSheet);
    	statusBar().showMessage(tr("Square "+((char)(x+65))+(8-y)+" selected"));
    	
    	// Finds possible moves.
    	int[][] possibleMoves = board.listMoves(clicked);
    	
    	/* Choose correct icons for the move and attackable area */
    	if(possibleMoves != null){
	    	for (int[] move : possibleMoves){
	    		buttons[move[0]][move[1]].setStyleSheet(findStyleSheet(board.getPiece(move[0], move[1]), 2));
	    	}
    	}
    	
    	/* 
    	 * Stores coords of clicked button and exits. If movable area, 
    	 * or attackable piece is selected this will be handled during the next call to the calling method.  
    	 */
    	oldx = x;
    	oldy = y;
    	oldMoves = possibleMoves;
    	
    	
    }
    
    
    /**
     * Method that removes colors from previously selected fields
     */
    private void removeOldMarkedFields(){
    	/* Remove old blue selection if present */
    	if(oldx > -1){
    		buttons[oldx][oldy].setStyleSheet(findStyleSheet(board.getPiece(oldx, oldy), 0));
    	}
    	
    	/* Removes old red fields (possible move-to locations) */
    	if(oldMoves != null){
	    	for (int[] move : oldMoves){
	    		buttons[move[0]][move[1]].setStyleSheet(findStyleSheet(board.getPiece(move[0], move[1]), 0));
	    	}
    	}
    }
    
    
    /**
     * Function that finds the correct stylesheet for the given piece.
     * @param piece The piece to find stylesheet for or null, if no piece is selected.
     * @param color Integer between 0 and 2.
     * 0: transparent
     * 1: blue
     * 2: red
     * @return String with the stylesheet. If piece is null. Stylesheet for blank button is returned.
     */
    private String findStyleSheet(Piece piece, int color){
    	if ((2 < color) || (color < 0)) return null;
    	if (piece == null){
    		return pieces_style[0][color];
    	}
    	String className = piece.getClass().getSimpleName();
    	int addForBlack = 0;
    	if(piece.getColor() == ChessColor.BLACK){ addForBlack = 6; }
    	
    	/* 
    	 * pawn, knight, bishop, rook, queen, king
    	 * white 1 - 6, black 7 - 12
    	 */
    	if 		(className.equalsIgnoreCase("pawn"))	{ return pieces_style[1 + addForBlack][color]; }
    	else if (className.equalsIgnoreCase("knight"))	{ return pieces_style[2 + addForBlack][color]; }
    	else if (className.equalsIgnoreCase("bishop"))	{ return pieces_style[3 + addForBlack][color]; }
    	else if (className.equalsIgnoreCase("rook"))	{ return pieces_style[4 + addForBlack][color]; }
    	else if (className.equalsIgnoreCase("queen"))	{ return pieces_style[5 + addForBlack][color]; }
    	else if (className.equalsIgnoreCase("king"))	{ return pieces_style[6 + addForBlack][color]; }
    	return null;
    }
    
    
    /**
     * Method that checks if a player is in a stalemate position when a game is loaded
     */
    private void checkStaleMateOnLoad(){
    	boolean isItBlack = false;
		if (((isItBlack = board.isStaleMate(ChessColor.BLACK)) == true) || (board.isStaleMate(ChessColor.WHITE))){
			gameOver = true;
			if(isItBlack){
				if(board.isCheck(board.findPiece(ChessColor.BLACK, "king"))){
					statusBar().showMessage(ChessColor.BLACK + " is checkmate!");
				}else{
					statusBar().showMessage(ChessColor.BLACK + " is stalemate! (No legal moves left, but not in check)");
				}
				endGame(ChessColor.BLACK);
			}else{
				if(board.isCheck(board.findPiece(ChessColor.WHITE, "king"))){
					statusBar().showMessage(ChessColor.WHITE + " is checkmate!");
				}else{
					statusBar().showMessage(ChessColor.WHITE + " is stalemate! (No legal moves left, but not in check)");
				}
				endGame(ChessColor.WHITE);
			}
		}else {
			gameOver = false;
			draw = false;
		}
    }
    
    
    /**
     * Method that puts the eliminated pieces on the right side of the board.
     */
    private void checkEliminated(){
    	
    	blackGone = board.getBlackGone();
    	whiteGone = board.getWhiteGone();
    	
    	
    	if(blackGone.size() > blackGoneSize){
    		int nr = blackGone.size() - 1;
        	if(nr <= 3){
        		eliminated[nr][0].setStyleSheet(findStyleSheet(blackGone.get(nr),0));
        	}else if(nr > 3 && nr < 8){
       			eliminated[nr-4][1].setStyleSheet(findStyleSheet(blackGone.get(nr),0));
       		}else if(nr > 7 && nr < 12){
       			eliminated[nr-8][2].setStyleSheet(findStyleSheet(blackGone.get(nr),0));
       		}else{
       			eliminated[nr-12][3].setStyleSheet(findStyleSheet(blackGone.get(nr),0));
       		}
        	blackGoneSize = blackGone.size();
        	
    	}if(whiteGone.size() > whiteGoneSize){
        	int nr = whiteGone.size() - 1;
    		if(nr < 4){
        		eliminated[nr][7].setStyleSheet(findStyleSheet(whiteGone.get(nr),0));
       		}else if(nr > 3 && nr < 8){
       			eliminated[nr-4][6].setStyleSheet(findStyleSheet(whiteGone.get(nr),0));
       		}else if(nr > 7 && nr < 12){
       			eliminated[nr-8][5].setStyleSheet(findStyleSheet(whiteGone.get(nr),0));
       		}else{
       			eliminated[nr-12][4].setStyleSheet(findStyleSheet(whiteGone.get(nr),0));
       		}	
         	whiteGoneSize = whiteGone.size();
    	}
    }
    
    
    /**
     * This method is used when loading a game, it goes through the blackGone and whiteGone lists and
     * loads the correct graphic on the buttons.
     */
    private void loadEliminated(){
    	blackGone = board.getBlackGone();
    	whiteGone = board.getWhiteGone();
    	
    	for(int i = 0; i < blackGone.size(); i++){
    		if(i <= 3){
    			eliminated[i][0].setStyleSheet(findStyleSheet(blackGone.get(i),0));
    		}else if(i > 3 && i < 8){
    			eliminated[i-4][1].setStyleSheet(findStyleSheet(blackGone.get(i),0));
    		}else if(i > 7 && i < 12){
    			eliminated[i-8][2].setStyleSheet(findStyleSheet(blackGone.get(i),0));
    		}else{
    			eliminated[i-12][3].setStyleSheet(findStyleSheet(blackGone.get(i),0));
    		}
    	}
    	for(int i = 0; i < whiteGone.size(); i++){
    		if(i < 4){
    			eliminated[i][7].setStyleSheet(findStyleSheet(whiteGone.get(i),0));
    		}else if(i > 3 && i < 8){
    			eliminated[i-4][6].setStyleSheet(findStyleSheet(whiteGone.get(i),0));
    		}else if(i > 7 && i < 12){
    			eliminated[i-8][5].setStyleSheet(findStyleSheet(whiteGone.get(i),0));
    		}else{
    			eliminated[i-12][4].setStyleSheet(findStyleSheet(whiteGone.get(i),0));
    		}	
    	}
    	
    }
    
    /**
     * Method that resets the eliminated widget to transparent buttons
     */
    private void clearEliminated(){
    	if(eliminated !=null){
	    	for (QPushButton[] element : eliminated) {
	    		for(int j = 0; j < eliminated[0].length; j++){
	    			element[j].setStyleSheet(findStyleSheet(null,0));
	    		}
	    	}
    	}
    }
    
    /**
     * This method opens a window and lets you choose a piece to replace a pawn that
     * has made it across the board.
     * @param piece
     */
    private void promotePawn(Piece piece){
    	convertX = piece.getXcoord();
    	convertY = piece.getYcoord();
    	convertBox = new QWidget();
    	convertBox.setWindowTitle("Choose piece to replace pawn");
    	QHBoxLayout convertBoxLayout = new QHBoxLayout(convertBox);
    	convertBoxLayout.setSpacing(0);
    	convertBoxLayout.setContentsMargins(4, 4, 4, 4);
    	QPushButton[] convertButtons = new QPushButton[4];
    	for(int i = 0; i < convertButtons.length; i++){
    		convertButtons[i] = new QPushButton();
    		convertButtons[i].setSizePolicy(buttonSize);
    		convertButtons[i].clicked.connect(this,"pawnPromoter"+i+"()");
    		convertButtons[i].clicked.containingObject();
    		convertBoxLayout.addWidget(convertButtons[i]);
    	}
    	if(piece.getColor() == ChessColor.BLACK){
        	convertBox.setWindowIcon(new QIcon(IMAGEPATH+"/pieces/00b_pawn.png"));
        	convertButtons[0].setStyleSheet(pieces_style[8][0]);
        	convertButtons[1].setStyleSheet(pieces_style[9][0]);
        	convertButtons[2].setStyleSheet(pieces_style[10][0]);
        	convertButtons[3].setStyleSheet(pieces_style[11][0]);
    	}else{
    		convertBox.setWindowIcon(new QIcon(IMAGEPATH+"/pieces/00w_pawn.png"));
    		convertButtons[0].setStyleSheet(pieces_style[2][0]);
        	convertButtons[1].setStyleSheet(pieces_style[3][0]);
        	convertButtons[2].setStyleSheet(pieces_style[4][0]);
        	convertButtons[3].setStyleSheet(pieces_style[5][0]);
    	}
    	convertBox.setWindowFlags(Qt.WindowType.SubWindow);
    	convertBox.setFixedSize((int) (chessboardSizeX/3), chessboardSizeY/8);
    	convertBox.setWindowModality(Qt.WindowModality.ApplicationModal);
    	convertBox.show();
    }
    
    /**
     * Method to handle what to do when a game is won
     * 
     * @param color
     * (ChessColor)<br />
     * Color that do not have anymore time left
     */
	void endGame(ChessColor color) {
		gameOver = true;
		stopClock();
		int winner = -1;
		if((color == ChessColor.BLACK) && board.hasSufficientMatingMaterials(ChessColor.WHITE) && !draw){
			
			//White won
			winner = 1;
		}else if((color == ChessColor.WHITE) && board.hasSufficientMatingMaterials(ChessColor.WHITE) && !draw){
			
			//Black won
			winner = 2;
		}else if(( (color == ChessColor.BLACK) && !board.hasSufficientMatingMaterials(ChessColor.WHITE) )
				|| ( (color == ChessColor.WHITE) && !board.hasSufficientMatingMaterials(ChessColor.BLACK)) 
				|| draw){
		
			//Draw
			winner = 0;
		}
		if(networkConnection != null){
			networkConnection.closeAll();
			networkConnection = null;
			networkIn = null;
			networkOut = null;
			networkURL = "";
		}
		endGameDialog(winner);
	}
	
	private void endGameDialog(int winner){
		String winnerText = null;
		if(winner==1){
			winnerText = "<center>The game was won <br /> by:<br />White</center>";
		}else if(winner ==2){
			winnerText = "<center>The game was won <br /> by:<br />Black</center>";
		}else{
			winnerText = "<center>The game was <br />a <br >draw</center>";
		}
    	QDialog endGame = new QDialog();
    	
        endGame.setMaximumSize(300, 200);
        endGame.setMinimumSize(300, 200);
    	QVBoxLayout endGameLayout = new QVBoxLayout(endGame);
    	QLabel endLabel = new QLabel(winnerText);
    	QPushButton endGameButton = new QPushButton("Close");
    	QFont endFont = new QFont();
    	endFont.setPointSize(20);
    	endFont.setBold(true);
    	
    	endLabel.setFont(endFont);
    	endGameButton.clicked.connect(endGame, "close()");
    	endGameButton.setGeometry(120, 170, 40, 10);
    	
    	endGameLayout.addWidget(endLabel);
    	endGameLayout.addWidget(endGameButton);
    	
    	endGame.setLayout(endGameLayout);
    	endGame.setWindowTitle("Winner");
    	endGame.setModal(true);
    	endGame.show();
    }
    
    /*
     * Methods to listen for the buttons and send a number as a string to boardListenDo(String nr)
     */
    @SuppressWarnings("unused")	private void chessListen00(){boardButtonListener(""+0+0);}
    @SuppressWarnings("unused")private void chessListen01(){boardButtonListener(""+0+1);}
    @SuppressWarnings("unused")private void chessListen02(){boardButtonListener(""+0+2);}
    @SuppressWarnings("unused")private void chessListen03(){boardButtonListener(""+0+3);}
    @SuppressWarnings("unused")private void chessListen04(){boardButtonListener(""+0+4);}
    @SuppressWarnings("unused")private void chessListen05(){boardButtonListener(""+0+5);}
    @SuppressWarnings("unused")private void chessListen06(){boardButtonListener(""+0+6);}
    @SuppressWarnings("unused")private void chessListen07(){boardButtonListener(""+0+7);}
    @SuppressWarnings("unused")private void chessListen10(){boardButtonListener(""+10);}
    @SuppressWarnings("unused")private void chessListen11(){boardButtonListener(""+11);}
    @SuppressWarnings("unused")private void chessListen12(){boardButtonListener(""+12);}
    @SuppressWarnings("unused")private void chessListen13(){boardButtonListener(""+13);}
    @SuppressWarnings("unused")private void chessListen14(){boardButtonListener(""+14);}
    @SuppressWarnings("unused")private void chessListen15(){boardButtonListener(""+15);}
    @SuppressWarnings("unused")private void chessListen16(){boardButtonListener(""+16);}
    @SuppressWarnings("unused")private void chessListen17(){boardButtonListener(""+17);}
    @SuppressWarnings("unused")private void chessListen20(){boardButtonListener(""+20);}
    @SuppressWarnings("unused")private void chessListen21(){boardButtonListener(""+21);}
    @SuppressWarnings("unused")private void chessListen22(){boardButtonListener(""+22);}
    @SuppressWarnings("unused")private void chessListen23(){boardButtonListener(""+23);}
    @SuppressWarnings("unused")private void chessListen24(){boardButtonListener(""+24);}
    @SuppressWarnings("unused")private void chessListen25(){boardButtonListener(""+25);}
    @SuppressWarnings("unused")private void chessListen26(){boardButtonListener(""+26);}
    @SuppressWarnings("unused")private void chessListen27(){boardButtonListener(""+27);}
    @SuppressWarnings("unused")private void chessListen30(){boardButtonListener(""+30);}
    @SuppressWarnings("unused")private void chessListen31(){boardButtonListener(""+31);}
    @SuppressWarnings("unused")private void chessListen32(){boardButtonListener(""+32);}
    @SuppressWarnings("unused")private void chessListen33(){boardButtonListener(""+33);}
    @SuppressWarnings("unused")private void chessListen34(){boardButtonListener(""+34);}
    @SuppressWarnings("unused")private void chessListen35(){boardButtonListener(""+35);}
    @SuppressWarnings("unused")private void chessListen36(){boardButtonListener(""+36);}
    @SuppressWarnings("unused")private void chessListen37(){boardButtonListener(""+37);}
    @SuppressWarnings("unused")private void chessListen40(){boardButtonListener(""+40);}
    @SuppressWarnings("unused")private void chessListen41(){boardButtonListener(""+41);}
    @SuppressWarnings("unused")private void chessListen42(){boardButtonListener(""+42);}
    @SuppressWarnings("unused")private void chessListen43(){boardButtonListener(""+43);}
    @SuppressWarnings("unused")private void chessListen44(){boardButtonListener(""+44);}
    @SuppressWarnings("unused")private void chessListen45(){boardButtonListener(""+45);}
    @SuppressWarnings("unused")private void chessListen46(){boardButtonListener(""+46);}
    @SuppressWarnings("unused")private void chessListen47(){boardButtonListener(""+47);}
    @SuppressWarnings("unused")private void chessListen50(){boardButtonListener(""+50);}
    @SuppressWarnings("unused")private void chessListen51(){boardButtonListener(""+51);}
    @SuppressWarnings("unused")private void chessListen52(){boardButtonListener(""+52);}
    @SuppressWarnings("unused")private void chessListen53(){boardButtonListener(""+53);}
    @SuppressWarnings("unused")private void chessListen54(){boardButtonListener(""+54);}
    @SuppressWarnings("unused")private void chessListen55(){boardButtonListener(""+55);}
    @SuppressWarnings("unused")private void chessListen56(){boardButtonListener(""+56);}
    @SuppressWarnings("unused")private void chessListen57(){boardButtonListener(""+57);}
    @SuppressWarnings("unused")private void chessListen60(){boardButtonListener(""+60);}
    @SuppressWarnings("unused")private void chessListen61(){boardButtonListener(""+61);}
    @SuppressWarnings("unused")private void chessListen62(){boardButtonListener(""+62);}
    @SuppressWarnings("unused")private void chessListen63(){boardButtonListener(""+63);}
    @SuppressWarnings("unused")private void chessListen64(){boardButtonListener(""+64);}
    @SuppressWarnings("unused")private void chessListen65(){boardButtonListener(""+65);}
    @SuppressWarnings("unused")private void chessListen66(){boardButtonListener(""+66);}
    @SuppressWarnings("unused")private void chessListen67(){boardButtonListener(""+67);}
    @SuppressWarnings("unused")private void chessListen70(){boardButtonListener(""+70);}
    @SuppressWarnings("unused")private void chessListen71(){boardButtonListener(""+71);}
    @SuppressWarnings("unused")private void chessListen72(){boardButtonListener(""+72);}
    @SuppressWarnings("unused")private void chessListen73(){boardButtonListener(""+73);}
    @SuppressWarnings("unused")private void chessListen74(){boardButtonListener(""+74);}
    @SuppressWarnings("unused")private void chessListen75(){boardButtonListener(""+75);}
    @SuppressWarnings("unused")private void chessListen76(){boardButtonListener(""+76);}
    @SuppressWarnings("unused")private void chessListen77(){boardButtonListener(""+77);}
    @SuppressWarnings("unused")private void chessListen(){System.out.println("?");};
    
    /**
     * Main creates a new application<br />
     * Sets size of application<br />
     * Sets window title and window icon
     * 
     * @param args
     */
    public static void main(String[] args) {
        QApplication.initialize(args);
        ChessGUI application = new ChessGUI();
        application.setMaximumSize(chessboardSizeX, chessboardSizeY);
        application.setMinimumSize(chessboardSizeX, chessboardSizeY);
        application.setWindowTitle("Chessboat 2010\u2122");
        application.setWindowIcon(new QIcon(IMAGEPATH+"pieces/00b_king.png"));
        application.show();
        QApplication.exec();
    }
}